import { Injectable } from '@angular/core';
import { ConfigProvider } from '../config/config';

/*
  Generated class for the RmiProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/

declare var Stomp;

@Injectable()
class RmiProvider {

  private isConnect: boolean = false;
  private client: any;
  private commands: SubscribeHandler[] = [];
  private executes: any[] = [];

  public constructor(private config: ConfigProvider) {
    this.init();
  }

  private init() {
    let connect = () => {
      let ws = new WebSocket(this.config.messageQueueWebSocketAddress);
      this.client = Stomp.over(ws);
      this.client.heartbeat.outgoing = 10000;
      this.client.heartbeat.incoming = 10000;
      let on_connect = (x) => {
        this.isConnect = true;
        while (this.commands.length > 0) {
          let command = this.commands.pop();
          if (!command.getIsCanceled()) {
            let s = this.subscribe(command.getParams().destionation, command.getParams().callback, command.getParams().conf);
            command.subscribe = s.subscribe;
          }
        }
        while (this.executes.length > 0) {
          let execute = this.executes.pop();
          this.execute(execute.destionation, execute.conf, execute.msg);
        }
      };
      let on_failure = function () {
        this.isConnect = false;
        let reConnect = setTimeout(() => {
          clearTimeout(reConnect);
          connect();
        }, 2000);
      };
      this.client.connect(this.config.messageQueueUsername, this.config.messageQueuePassword, on_connect, on_failure, this.config.messageQueueVirtualhost);
    };
    connect();
  }

  public execute(destionation, conf, msg): void {
    if (this.isConnect) {
      let message = typeof msg == 'string' ? msg : JSON.stringify(msg);
      this.client.send(destionation, conf ? conf : {}, message);
    } else {
      this.executes.push({
        destionation: destionation,
        conf: conf,
        msg: msg
      });
    }
  }

  public subscribe(destionation, callback, conf): SubscribeHandler {
    if (this.isConnect) {
      let handler = new SubscribeHandler({
        destionation: destionation,
        callback: callback,
        conf: conf
      }, this.client.subscribe(
        destionation,
        callback,
        conf ? conf : {
          durable: false,
          exclusive: false
        }
      )
      );
      return handler;
    } else {
      let handler = new SubscribeHandler({
        destionation: destionation,
        callback: callback,
        conf: conf
      }, undefined);
      this.commands.push(handler);
      return handler;
    }
  }
}

class SubscribeHandler {

  private canceled: boolean = false;

  constructor(private params: any, public subscribe: any) {
    this.canceled = false;
  }

  getIsCanceled() {
    return this.canceled;
  }

  getParams() {
    return this.params;
  }

  cancelSubscribe() {
    this.canceled = true;
    if (this.subscribe) {
      this.subscribe.unsubscribe();
    }
  }

}

export { RmiProvider, SubscribeHandler }